package java_thinking.unit_21._21_10;

/**
 * @Desc:   10-3    通过锁顺序来避免死锁
 *          1.通过计算对象的哈希值并排序，将多种顺序锁限制为固定顺序来对对象进行上锁
 * @author: cww
 * @DateTime: 2019-06-19 23:59
 */

public class InduceLockOrder {
    private static final Object tieLock = new Object();
    public void transferMoney (final Account fromAcct, final Account toAcct, final DollarAmount amount) throws InsufficientFundsException {
        class Helper {
            public void transger() throws InsufficientFundsException {
                if (fromAcct.getBalance().compareTo(amount) < 0) {
                    throw new InsufficientFundsException();
                } else {
                    fromAcct.debit(amount);
                    toAcct.credit(amount);
                }
            }
        }
        //极少数情况两个对象可能拥有相同的散列值，此时必须通过某种任意的方法来决定锁顺序，而这可能又会重新引入死锁
        //为避免这种情况可以用“加时赛”(TieBreaking)锁,在获得两个对象锁之前，先获得的这个“加时赛”锁-tieLock，从而
        //保证一个线程以未知的顺序获得这两个锁，从而消除死锁发生的可能性(前提是多个相关线程都用这个机制)
        int fromHash = System.identityHashCode(fromAcct);
        int toHash = System.identityHashCode(toAcct);

        if (fromHash < toHash) {
            synchronized (fromAcct) {
                synchronized (toAcct) {
                    new Helper().transger();
                }
            }
        } else if (fromHash > toHash) {
            synchronized (toAcct) {
                synchronized (fromAcct) {
                    new Helper().transger();
                }
            }
        } else {
            synchronized (tieLock) {
                synchronized (toAcct) {
                    synchronized (fromAcct) {
                        new Helper().transger();
                    }
                }
            }
        }
    }


    interface Account {
        void debit(DollarAmount d);

        void credit(DollarAmount d);

        DollarAmount getBalance();

        int getAcctNo();
    }
    interface DollarAmount extends Comparable<DollarAmount> {
    }

    class InsufficientFundsException extends Exception {
    }

}
